package gee

import (
	"fmt"
	"net/http"
	"strings"
)

// 定义路由层的request handler：用来定义路由映射的处理方法
type HandlerFunc func(*Context)

// 定义Engine为handler对象，实现ServeHttp接口--继承路由组
type Engine struct {
	*RouterGroup
	router *Router        // 路由
	groups []*RouterGroup // 路由组
}

// 创建 gee.Engine
func New() *Engine {
	engine := &Engine{router: newRouter()}
	engine.RouterGroup = &RouterGroup{engine: engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
}

// 将路由set到映射表中
func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {
	engine.router.addRoute(method, pattern, handler)
}

// Get方法
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
	engine.addRoute("GET", pattern, handler)
}

// Post方法
func (engine *Engine) POST(pattern string, handler HandlerFunc) {
	engine.addRoute("POST", pattern, handler)
}

// 开启web服务
func (engine *Engine) Run(addr string) (err error) {
	return http.ListenAndServe(addr, engine)
}

// 实现ServeHTTP接口方法 ： 查找路由映射表，如果查到，就执行注册的处理方法。如果查不到，就返回 404 NOT FOUND 。
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var middlewares []HandlerFunc
	// 循环所有的路由组 路由相同的 中间件取出放到 c 的操作集合中
	for _, group := range engine.groups {
		if strings.HasPrefix(req.URL.Path, group.basePath) {
			middlewares = append(middlewares, group.middlewares...)
		}
	}

	c := newContext(w, req)
	c.handlers = middlewares
	engine.router.handle(c)
}

// 路由不存在
func (engine *Engine) NoRoute(w http.ResponseWriter, req *http.Request) {
	w.WriteHeader(http.StatusNotFound)
_:
	fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}

// 路由接口
type IRoutes interface {
	IRoute
	Group(string) *RouterGroup
}

type IRoute interface {
	GET(string, HandlerFunc)
	POST(string, HandlerFunc)
}

// 路由组：前缀和中间件--实现IRoutes接口
type RouterGroup struct {
	basePath    string
	engine      *Engine
	middlewares []HandlerFunc
}

// 创建一个新的路由组
func (group *RouterGroup) Group(prefix string) *RouterGroup {
	newGroup := &RouterGroup{
		basePath: group.basePath + prefix,
		engine:   group.engine,
	}
	group.engine.groups = append(group.engine.groups, newGroup)
	return newGroup
}

// 中间件添加
func (group *RouterGroup) Use(middlewares ...HandlerFunc) {
	group.middlewares = append(group.middlewares, middlewares...)
}

func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) {
	group.engine.router.addRoute(method, group.basePath+comp, handler)
}

func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
	group.addRoute("GET", pattern, handler)
}

func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
	group.addRoute("POST", pattern, handler)
}
